/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-14 17:39:31
 * @Description  : 分享接口控制器
 */
const { Op } = require('sequelize')
const R = require('@/models/Response')
const {
  Share,
  ShareTo,
  User,
  Source,
  Department,
  UserDepartment
} = require('@/models/model')
const { ERROR_SHARE_CODE, ERROR_SOURCE_CODE } = require('@/constants/errorCode')
const { generatId } = require('@/utils/idUtil')
const { delModel, listModel } = require('@/utils/controllerCommon')
const Mysequelize = require('../models')
const { SEPARATE_CHAR } = require('../constants')
const { sourceAttr, sourceInclude } = require('./sourceController')
const { LOG_TYPE } = require('@/constants/log')

/**
 * 列表查询分享接口
 * @param {*} ctx
 * @returns
 */
module.exports.listShare = async (ctx) => {
  const { type, userId, startTime, endTime } = ctx.newQuery
  // console.log(startTime, endTime, 'xxxxxxxxxxxxxxxxxxxxxx')
  const whereCondition = {}
  if (type !== undefined) {
    whereCondition.isLink = type === 0 ? 1 : 0
    whereCondition.isShareTo = type === 1 ? 1 : 0
  }
  if (userId) {
    whereCondition.createUser = userId
  }
  whereCondition.createTime = {}
  if (startTime) {
    whereCondition.createTime = {
      ...whereCondition.createTime,
      [Op.gt]: new Date(startTime)
    }
  }
  if (endTime) {
    whereCondition.createTime = {
      ...whereCondition.createTime,
      [Op.lt]: new Date(endTime)
    }
  }

  // console.log(whereCondition)
  if (JSON.stringify(whereCondition) === '{}') {
    delete whereCondition.createTime
  }

  // console.log(whereCondition)
  // const orderCondition = [['sort']]
  await listModel(Share)(ctx, whereCondition, undefined, undefined, [
    {
      model: User,
      attributes: ['id', 'username', 'avator']
    }
  ])
}

/**
 * 根据分享ID获取外链分享详情
 * @param {} ctx
 */
module.exports.listLinkShareById = async (ctx) => {
  const { shareId } = ctx.query
  const share = await Share.findOne({
    where: {
      id: BigInt(shareId),
      isLink: 1
    },
    include: [
      {
        model: Source,
        as: 'source',
        attributes: {
          include: [
            [
              Mysequelize.literal(
                '(SELECT COUNT(*) FROM source AS sc WHERE sc.parent_id = source.id and sc.is_dir = 0 and sc.delete_flag = 0)'
              ),
              'hasFile'
            ],
            [
              Mysequelize.literal(
                '(SELECT COUNT(*) FROM source AS sc WHERE sc.parent_id = source.id and sc.is_dir = 1 and sc.delete_flag = 0)'
              ),
              'hasFolder'
            ],
            [
              Mysequelize.literal(
                `CASE WHEN EXISTS (SELECT 1 FROM source as sc WHERE sc.parent_id = source.id and sc.delete_flag=0) THEN 0 ELSE 1 END`
              ),
              'isLeaf'
            ]
          ]
        }
      }
    ]
  })
  if (!share) {
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_ID_ERROR)
    return
  }
  let finalShare = share.toJSON()
  if (!finalShare.code) {
    finalShare.code = 0
  } else {
    finalShare.code = 1
  }

  // 获取创建用户
  const user = await User.findByPk(BigInt(finalShare.createUser), {
    attributes: ['id', 'username', 'nickname', 'avator']
  })

  finalShare.User = user

  ctx.body = R.success(finalShare)
}

/**
 * 用户列表查询自己的分享接口
 * @param {*} ctx
 * @returns
 */
module.exports.listUserShare = async (ctx) => {
  const { page, pageSize, type, filename } = ctx.newQuery
  const start = (page - 1) * pageSize

  let sourceWhere = {}
  if (filename) {
    sourceWhere.filename = {
      [Op.like]: `%${filename}%`
    }
  } else {
    sourceWhere = undefined
  }

  const whereCondition = { updateUser: BigInt(ctx.user.id) }
  if (+type === 0) {
    whereCondition.isLink = 1
  } else {
    whereCondition.isShareTo = 1
  }

  let { rows, count } = await Share.findAndCountAll({
    where: whereCondition,
    include: [
      {
        model: Source,
        as: 'source',
        attributes: sourceAttr,
        include: sourceInclude,
        where: sourceWhere,
        required: true
      }
    ],
    order: [['updateTime', 'DESC']],
    limit: +pageSize,
    offset: +start
  })

  // 对于source，需要查询出path

  for (let i = 0; i < rows.length; i++) {
    let source = rows[i].source.toJSON()
    // 查询出source的parentLevel

    const parentNames = source.parentLevel
      .split(SEPARATE_CHAR)
      .filter((item) => item !== '-1')
      .concat([source.id])
      .map((item) => BigInt(item))

    // 查询出相关的信息
    const ppSources = await Source.findAll({
      where: {
        id: {
          [Op.in]: parentNames
        }
      },
      attribute: ['id', 'filename'],
      order: [
        Mysequelize.literal(`FIELD(id, ${parentNames.join(',')})`) // 按指定 ID 数组顺序排序
      ]
    })

    // 赋值给当前source
    const curPathInfo = ppSources.map((item) => {
      return {
        id: item.id,
        filename: item.filename
      }
    })
    // source = source.toJSON()
    source.pathInfo = curPathInfo
    rows[i].dataValues.source = source
  }

  ctx.body = R.success({
    page,
    pageSize,
    items: rows,
    total: count,
    pages: Math.ceil(count / pageSize)
  })
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新内部分享授权的对象
 * @param {*} authTo 授权对象数组
 * @param {*} shareId 分享ID
 * @param {*} userId 用户ID
 * @param {*} t 事务对象
 */
const updateShareTo = async (authTo, shareId, userId, t) => {
  let newAuthTo = authTo.map((item) => {
    let obj = {
      ...item,
      id: generatId(),
      shareId,
      createUser: userId,
      updateUser: userId
    }
    return obj
  })
  await ShareTo.bulkCreate(newAuthTo, { transaction: t })
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建分享接口
 * @param {*} ctx
 */
module.exports.createShare = async (ctx) => {
  const { title, sourceId, isLink, isShareTo, deadline, code, options } =
    ctx.request.body
  const t = await Mysequelize.transaction()
  const nextId = generatId()

  let createObj = {
    id: nextId,
    title,
    sourceId,
    isLink: isLink || 0,
    isShareTo: isShareTo || 0,
    deadline: deadline ? +deadline : 0,
    code: code || '',
    options: options
      ? JSON.stringify(options)
      : JSON.stringify({
          forbidNotLogin: '0',
          forbidView: '0',
          forbidDownload: '0',
          downloadLimitCnt: '0'
        }),
    isActive: 1,
    numView: 0,
    numDownload: 0,
    createUser: ctx.user.id,
    updateUser: ctx.user.id
  }

  try {
    // 到这里可以进行分享的添加了
    const share = await Share.create(createObj, {
      transaction: t
    })
    // 操作分享对应的权限
    // await updateSharePermission(permissionIds, nextId, ctx.user.id, t)
    await t.commit()
    // ctx.logs = {
    //   roldId: share.id
    // }
    ctx.body = R.success()
  } catch (error) {
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_CREATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 处理外链分享的更新
 * @param {*} ctx
 */
const updateLinkShare = async (ctx) => {
  const { title, code, deadline, options, shareId, isActive } = ctx.request.body
  const t = await Mysequelize.transaction()
  const updateObj = {
    title,
    code,
    isLink: 1
  }
  deadline !== undefined && (updateObj.deadline = deadline)
  options !== undefined && (updateObj.options = JSON.stringify(options))
  isActive !== undefined && (updateObj.isActive = isActive)

  try {
    await Share.update(updateObj, {
      where: {
        id: BigInt(shareId)
      },
      transaction: t
    })
    await t.commit()
    // 日志记录
    const share = await Share.findByPk(BigInt(shareId))
    const source = await Source.findByPk(BigInt(share.sourceId))
    ctx.logs = [
      {
        type: LOG_TYPE.SOURCE_EXTEND_SHARE,
        share: share.toJSON(),
        curSource: source.toJSON(),
        mode: 'update',
        sourceIds: [share.sourceId, source.parentId].join(SEPARATE_CHAR)
      }
    ]
    ctx.body = R.success()
  } catch {
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_UPDATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 处理内部协作分享的更新
 * @param {*} ctx
 */
const updateInnerShare = async (ctx) => {
  const { authTo, shareId, deadline, options, isActive } = ctx.request.body
  const t = await Mysequelize.transaction()
  const updateObj = {
    isShareTo: 1
  }
  deadline !== undefined && (updateObj.deadline = deadline)
  options !== undefined && (updateObj.options = JSON.stringify(options))
  isActive !== undefined && (updateObj.isActive = isActive)

  try {
    await Share.update(updateObj, {
      where: {
        id: BigInt(shareId)
      },
      transaction: t
    })

    // 更新分享授权对象，删除对应的记录
    await ShareTo.destroy({
      where: {
        shareId: BigInt(shareId)
      },
      transaction: t
    })
    // 重新添加
    await updateShareTo(authTo, shareId, ctx.user.id, t)

    // 日志记录
    const share = await Share.findByPk(BigInt(shareId))
    const source = await Source.findByPk(BigInt(share.sourceId))
    ctx.logs = [
      {
        type: LOG_TYPE.SOURCE_INNER_SHARE,
        share: share.toJSON(),
        curSource: source.toJSON(),
        mode: 'update',
        sourceIds: [share.sourceId, source.parentId].join(SEPARATE_CHAR)
      }
    ]
    await t.commit()
    ctx.body = R.success()
  } catch (error) {
    console.log(error)
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_UPDATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新分享接口
 * @param {*} ctx
 */
module.exports.updateShare = async (ctx) => {
  const { isLink, isShareTo } = ctx.request.body
  // 根据类型的不同去处理不同的分享
  if (isLink) {
    // 外链分享
    await updateLinkShare(ctx)
  } else if (isShareTo) {
    await updateInnerShare(ctx)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 用户取消分享接口
 * @param {*} ctx
 */
module.exports.cancelShare = async (ctx) => {
  const { shareIds, type } = ctx.request.body
  const t = await Mysequelize.transaction()
  let updateObj = {}

  if (+type === 1) {
    updateObj.isShareTo = 0
  } else {
    updateObj.isLink = 0
  }

  // 日志记录
  ctx.logs = []
  for (let i = 0; i < shareIds.length; i++) {
    const share = await Share.findByPk(BigInt(shareIds[i]))
    const source = await Source.findByPk(BigInt(share.sourceId))
    if (+type === 1 && !share.isShareTo) {
      continue
    }

    if (+type === 0 && !share.isLink) {
      continue
    }
    ctx.logs.push({
      type:
        +type === 1
          ? LOG_TYPE.SOURCE_INNER_SHARE
          : LOG_TYPE.SOURCE_EXTEND_SHARE,
      share: share.toJSON(),
      curSource: source.toJSON(),
      model: 'cancel',
      sourceIds: [share.sourceId, source.parentId].join(SEPARATE_CHAR)
    })
  }

  try {
    await Share.update(updateObj, {
      where: {
        id: {
          [Op.in]: shareIds.map((item) => BigInt(item))
        }
      }
    })

    await t.commit()
    ctx.body = R.success()
  } catch {
    await t.rollback()
    ctx.body = R.error(ERROR_SOURCE_CODE.CANCEL_SHARE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 开启/关闭分享接口
 * @param {*} ctx
 */
module.exports.setStatus = async (ctx) => {
  let { shareIds, status } = ctx.request.body
  shareIds = shareIds.map((v) => BigInt(v))
  const t = await Mysequelize.transaction()
  try {
    await Share.update(
      {
        isActive: status
      },
      {
        where: {
          id: {
            [Op.in]: shareIds
          }
        },
        transaction: t
      }
    )
    await t.commit()
    ctx.body = R.success()
  } catch {
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_STATUS_RRROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除分享接口
 * @param {*} ctx
 */
module.exports.delShares = async (ctx) => {
  // 根据分享类型的不同看是否需要进行shareTo表的删除
  await delModel(
    Share,
    ERROR_SHARE_CODE.SHARE_DEL_ERROR,
    'shareIds'
  )(ctx, [{ model: ShareTo, idName: 'shareId' }])
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 浏览数增加接口
 * @param {*} ctx
 */
module.exports.shareNumViewAdd = async (ctx) => {
  const { shareId } = ctx.request.body

  const t = await Mysequelize.transaction()
  try {
    const share = await Share.findByPk(BigInt(shareId))

    await Share.update(
      {
        numView: share.numView + 1
      },
      {
        where: {
          id: BigInt(shareId)
        },
        transaction: t
      }
    )

    await t.commit()
    ctx.body = R.success()
  } catch {
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_UPDATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 下载数增加接口
 * @param {*} ctx
 */
module.exports.shareNumDownloadAdd = async (ctx) => {
  const { shareId } = ctx.request.body

  const t = await Mysequelize.transaction()
  try {
    const share = await Share.findByPk(BigInt(shareId))

    await Share.update(
      {
        numDownload: share.numDownload + 1
      },
      {
        where: {
          id: BigInt(shareId)
        },
        transaction: t
      }
    )

    await t.commit()
    ctx.body = R.success()
  } catch {
    await t.rollback()
    ctx.body = R.error(ERROR_SHARE_CODE.SHARE_UPDATE_ERROR)
  }
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 获取分享给当前登录用户的内部分享列表
 * @param {*} ctx
 */
module.exports.listUserInnerShare = async (ctx) => {
  const { page, pageSize, filename } = ctx.query
  const whereCondition = {
    isShareTo: 1
  }
  let sourceWhere = undefined
  if (filename !== undefined) {
    sourceWhere = {
      filename: {
        [Op.like]: '%' + filename + '%'
      }
    }
  }

  const start = (page - 1) * pageSize
  const { rows, count } = await Share.findAndCountAll({
    where: whereCondition,
    include: [
      {
        model: Source,
        as: 'source',
        where: sourceWhere,
        attributes: sourceAttr
      },
      {
        model: ShareTo,
        include: [
          {
            required: false,
            model: User,
            where: {
              id: BigInt(ctx.user.id)
            }
          },
          {
            // required: false,
            required: false,
            model: Department
            // include: [
            //   {
            //     required: false,
            //     model: UserDepartment
            //     // where: {
            //     //   userId: BigInt(ctx.user.id)
            //     // }
            //   }
            // ]
          }
        ]
      }
    ],
    offset: +start,
    limit: +pageSize,
    order: [['updateTime', 'DESC']]
  })
  ctx.body = R.success({
    page,
    pageSize,
    total: count,
    pages: Math.ceil(count / pageSize),
    items: rows
  })
}
